// Copyright (c) 2010 Omer Goshen

#include <iostream>
#include <cstdio>

#include "HUD.h"

#define HUD_FONT "BerlinSans32"

using namespace std;
using namespace Ogre;

int i;

class OgreText : public FrameListener
{
public:
	OgreText(Ogre::Root* root)
	{
		this->root = root;
		root->addFrameListener(this);

		alpha = 0;
		aliveTime = 0;
		timeToLive = 2.0f;

		olm=OverlayManager::getSingletonPtr();
		if(init==0)
			{
				panel=static_cast<OverlayContainer*>(olm->createOverlayElement("Panel","GUI"));
				panel->setMetricsMode(Ogre::GMM_PIXELS);
				panel->setPosition(0,0);
				panel->setDimensions(1.0f,1.0f);
				overlay=olm->create("GUI_OVERLAY");
				overlay->add2D(panel);
				overlay->setZOrder(100);
			}
		++(this->init);
		szElement="element_"+StringConverter::toString(init);
		overlay=olm->getByName("GUI_OVERLAY");
		panel=static_cast<OverlayContainer*>(olm->getOverlayElement("GUI"));
		textArea=static_cast<TextAreaOverlayElement*>(olm->createOverlayElement("TextArea",szElement));
		panel->addChild(textArea);
		overlay->show();
	}
	~OgreText()
	{
		szElement="element_"+StringConverter::toString(init);
		olm->destroyOverlayElement(szElement);
		--(this->init);
		if(init==0)
			{
				olm->destroyOverlayElement("GUI");
				olm->destroy("GUI_OVERLAY");
			}
	}
	void setText(char *szString)
	{
		textArea->setCaption(szString);
		textArea->setDimensions(1.0f,1.0f);
		textArea->setMetricsMode(Ogre::GMM_RELATIVE);
		textArea->setFontName(HUD_FONT);
		textArea->setCharHeight(0.05f);
	}
	void setText(Ogre::String szString) // now You can use Ogre::String as text
	{
		textArea->setCaption(szString);
		textArea->setDimensions(1.0f,1.0f);
		textArea->setMetricsMode(Ogre::GMM_RELATIVE);
		textArea->setFontName(HUD_FONT);
		textArea->setCharHeight(0.05f);
	}

	void setPos(float x,float y) { textArea->setPosition(x,y); }
	void setCol(ColourValue col) { textArea->setColour(col); }
	void setCol(float R,float G,float B,float I) { textArea->setColour(Ogre::ColourValue(R,G,B,I));	}

	bool frameStarted(const FrameEvent& e)
	{
		aliveTime += e.timeSinceLastFrame;

		if(aliveTime > timeToLive && alpha==0.0f)
			{
				--i;
				root->removeFrameListener(this);
			}

		alpha += (aliveTime > timeToLive ? -1 : 1) * exp(1)*e.timeSinceLastFrame;

		alpha = min(1.0f, max(0.0f, alpha));

		setCol(1,1,1,alpha);

		return true;
	}

	bool frameEnded(const FrameEvent& e)
	{
		return true;
	}

	inline Real getWidth() { return textArea->getWidth(); }
	inline Real getHeight() { return textArea->getHeight(); }
private:
	Real alpha;
	Real timeToLive;
	Real aliveTime;

	Root* root;
	OverlayManager *olm;
	OverlayContainer *panel ;
	Overlay *overlay;
	TextAreaOverlayElement *textArea;
	static int init;
	Ogre::String szElement;
};

int OgreText::init=0;


class Graph2D : public FrameListener
{
public:
	Graph2D()
	{

		unsigned width  = 100;
		unsigned height = 100;

		tex = TextureManager::getSingleton().createManual("Graph2D", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		        TEX_TYPE_2D, width, height, 0,
		        PF_BYTE_BGRA,
		        TU_DEFAULT
//		        TU_DYNAMIC_WRITE_ONLY_DISCARDABLE
		                                                 ).get();



		MaterialPtr material = MaterialManager::getSingleton().create("Graph2D", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

		Ogre::TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState("Graph2D");
		//tus->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
		//tus->setTextureFiltering(TFO_NONE);
		material->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);

		OverlayManager* olm = OverlayManager::getSingletonPtr();


		panel = static_cast<OverlayContainer*>(olm->createOverlayElement("Panel", "Graph2DPanel"));

		panel->setMetricsMode(Ogre::GMM_PIXELS);
		panel->setPosition(0, 0);
		panel->setDimensions(width, height);
		panel->setMaterialName("Graph2D");


		overlay = olm->create("Graph2DOverlay");
		overlay->add2D(panel);
		overlay->show();

		clear();

		Ogre::Root::getSingleton().addFrameListener(this);
	}

	void clear()
	{
		unsigned int idx;
		int x, y;

		int texw=tex->getWidth();
		int texh=tex->getHeight();

		Ogre::HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();

		pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
		const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();

		Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);

		// FILL!
		for (x=0, y=0; y<texh; )
			{
				idx=(x*4)+y*pixelBox.rowPitch*4;

				// paint
				pDest[idx]=0;//b
				pDest[idx+1]=0;//g
				pDest[idx+2]=0;//r
				pDest[idx+3]=128;//a

				x++;
				if (x>=texw)
					{
						x=0;
						y++;
					}
			}


		pixelBuffer->unlock();
	}

	bool frameStarted(const FrameEvent& e)
	{
		lastUpdate += e.timeSinceLastFrame;
		if(lastUpdate<0.1) return true;
		lastUpdate = 0;

		pos.x++;
		if(pos.x > 100)
			{
				clear();
				pos.x=0;
			}

		FrameTimes fs = App::getSingleton().getFrameStats();
//		pos.y = 100 - int(100 * float(fs.render) / float(fs.total));
		pos.y = int(100 * float(fs.render) / float(fs.total));

//		Real bestFPS = App::getSingleton().getWindow()->getBestFPS();
//		Real currFPS = App::getSingleton().getWindow()->getLastFPS();
//		if(Math::isNaN(currFPS) || Math::isNaN(bestFPS) || bestFPS==0) return true;
//		pos.y = unsigned(100 * currFPS / (bestFPS+20));

		if(pos.y>100) pos.y=100;
		if(pos.y<0) pos.y=0;


		unsigned int idx;
		int x, y;

		int texw=tex->getWidth();
		int texh=tex->getHeight();

		Ogre::HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();

		pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
		const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();

		Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);

		for(unsigned i=texh-1; i>texh-pos.y; i--)
			{
				idx=(pos.x*4)+i*pixelBox.rowPitch*4;

				pDest[idx]=255;//b
				pDest[idx+1]=255;//g
				pDest[idx+2]=255;//r
				pDest[idx+3]=150;//a
			}

		pixelBuffer->unlock();


		return true;
	}

private:
	Overlay* overlay;
	OverlayContainer *panel ;

	Texture* tex;

	Ogre::Vector2 pos;

	Real lastUpdate;
};

HUD::HUD(Ogre::Root* root, SceneManager *sceneMgr, Camera* cam, RenderTarget *renderTarget) :
	mRoot(root),
	mSceneMgr(sceneMgr),
	mCamera(cam),
	mRenderTarget(renderTarget),
	mBuffer(0),
	mPixelBox(0)
{
	i = 0;
//    speed = 0;

	/*
		mMaterialSwitchListener = new HudMaterialSwitcher();
		mHudTargetListener = new HudRenderListener(mMaterialSwitchListener, mSceneMgr);


		unsigned int width = mRenderTarget->getWidth();
		unsigned int height = mRenderTarget->getHeight();

		mTexture = TextureManager::getSingleton().createManual("HudTex", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		           TEX_TYPE_2D, width, height, 0, PF_R8G8B8A8, TU_RENDERTARGET);

		mRenderTexture = mTexture->getBuffer()->getRenderTarget();
	//	mRenderTexture->setAutoUpdated(false);
		mRenderTexture->setAutoUpdated(true);
		mRenderTexture->setPriority(0);
		mRenderTexture->addViewport(mCamera);
		mRenderTexture->getViewport(0)->setBackgroundColour(ColourValue(1,1,1,0));
		mRenderTexture->getViewport(0)->setOverlaysEnabled(true);
		mRenderTexture->getViewport(0)->setClearEveryFrame(true);
		mRenderTexture->getViewport(0)->setSkiesEnabled(false);
	//	mRenderTexture->getViewport(0)->setClearEveryFrame(false);
	//	mRenderTexture->getViewport(0)->setClearEveryFrame(true, FBT_DEPTH|FBT_STENCIL);
		mRenderTexture->getViewport(0)->setMaterialScheme("hud");
		mRenderTexture->addListener(mHudTargetListener);

	*/

	Graph2D* g2d = new Graph2D();


	OverlayManager* olm = OverlayManager::getSingletonPtr();

	panel = static_cast<OverlayContainer*>(olm->createOverlayElement("Panel", "MainPanel"));

	panel->setMetricsMode(Ogre::GMM_RELATIVE);
	panel->setPosition(0, 0);
	panel->setDimensions(1, 1);
	panel->setMaterialName("HUD");
	panel->setParameter("transparent","true");

	overlay = olm->create("OverlayName");
	overlay->add2D(panel);
	overlay->show();

//    OgreText *textItem = new OgreText(root);

	mRoot->addFrameListener(this);

}

HUD::~HUD()
{
//    OverlayManager::getSingleton().destroyOverlayElement( speedTF );
//    OverlayManager::getSingleton().destroyOverlayElement( timerTF );
	OverlayManager::getSingleton().destroyOverlayElement( panel );
	OverlayManager::getSingleton().destroy( overlay );
}

void HUD::print(const Ogre::String& msg)
{
	i++;

	OgreText *textItem = new OgreText(mRoot);
	textItem->setText(msg);

//    textItem->setPos((1.f - textItem->getWidth())/2.f, 0.15f + i*textItem->getHeight());
	textItem->setPos(.01f, 0.1f + i*0.05f);
	textItem->setCol(1.0f,1.0f,1.0f,0.0f);

}

void HUD::toggle()
{
	if(overlay->isVisible())
		overlay->hide();
	else
		overlay->show();

	if(panel->isVisible())
		panel->hide();
	else
		panel->show();

}
